﻿using Newtonsoft.Json.Linq;
using PLCCommunication;
using PLCCommunication.LogNet;
using PLCCommunication.MQTT;
using System;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace WindowsService1
{
    public class MqttClientWrapper
    {
        private MqttClient mqttClient;
        private bool mqttIsConnected;
        private const int MaxReconnectAttempts = 5;
        private const int ReconnectDelay = 5000; // 5 seconds

        private MqttConnectionOptions options;
        public event Action<string, string, string> OnMessageReceived;
        public long ReceiveCount { get; private set; }

        public PLCCommunication.LogNet.ILogNet LogNet = new LogNetDateTime("D:\\APILog\\Logs\\MQTTLogs", GenerateMode.ByEveryDay, 20);

        public enum MessageFormat
        {
            Binary,
            Text,
            Xml,
            Json
        }


        public MqttClientWrapper(string ipAddress, int port, string clientId, MqttCredential credentials)
        {
            InitializeMqttOptions(ipAddress, port, clientId, credentials);
        }

        private void InitializeMqttOptions(string ipAddress, int port, string clientId, MqttCredential credentials)
        {
            options = new MqttConnectionOptions
            {
                IpAddress = ipAddress,
                Port = port,
                ClientId = clientId,
                Credentials = credentials,
                UseRSAProvider = false,
                CleanSession = false,
                UseSSL = false,
                SSLSecure = false,
                CertificateFile = "",
                KeepAlivePeriod = TimeSpan.FromSeconds(30),
                KeepAliveSendInterval = TimeSpan.FromSeconds(10),
                ConnectTimeout = 5,
                WillMessage = null
            };
        }

        public async Task InitializeAndConnectAsync()
        {
            try
            {
                mqttClient = new MqttClient(options);
                Logger.WriteMqtt("MQTT 初始化成功");

                await ConnectMqttAsync();
            }
            catch (Exception ex)
            {
                Logger.WriteError($"MQTT 初始化失败: {ex.Message}");
            }
        }

        private async Task ConnectMqttAsync()
        {
            try
            {
                JYResult connect = await mqttClient.ConnectServerAsync();
                if (connect.IsSuccess)
                {
                    mqttIsConnected = true;
                    Logger.WriteMqtt("MQTT 连接服务器成功");
                }
                else
                {
                    Logger.WriteError("MQTT 无法连接到服务器");
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError($"MQTT 无法连接到服务器: {ex.Message}");
            }
        }


        public async Task SendMessageAsync(string source, string publishTopic, string type, JObject messageObj)
        {
            if (!mqttClient.IsConnected)
            {
                mqttIsConnected = false;

                Logger.WriteMqtt("客户端未连接到服务器。正在尝试重新连接...");

                await ReconnectWithRetry();
                if (!mqttClient.IsConnected)
                {
                    throw new InvalidOperationException("无法与 MQTT 代理建立连接.");
                }
            }
            try
            {
                if (messageObj != null)
                {
                    string json = messageObj.ToString();
                    //string json = JsonConvert.SerializeObject(messageObj);
                    JYResult result = await mqttClient.PublishMessageAsync(new MqttApplicationMessage
                    {
                        Topic = publishTopic,
                        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce,
                        Payload = Encoding.UTF8.GetBytes(json),
                        Retain = false,
                    });
                    if (result.IsSuccess)
                    {
                        if (Service1.SwitchLog)
                        {
                            Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}]: {json}");
                        }
                    }
                    else
                    {
                        Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}] 失败: {result.Message}");

                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError($"发送消息错误: {ex.Message}");
            }
        }


        public async Task SendMessageAsync(string source, string publishTopic, string type, string messageObj)
        {
            if (!mqttClient.IsConnected)
            {
                mqttIsConnected = false;

                Logger.WriteMqtt("客户端未连接到服务器。正在尝试重新连接...");


                await ReconnectWithRetry();
                if (!mqttClient.IsConnected)
                {
                    throw new InvalidOperationException("无法与 MQTT 代理建立连接.");
                }
            }
            try
            {
                if (messageObj != null)
                {
                    JYResult result = await mqttClient.PublishMessageAsync(new MqttApplicationMessage
                    {
                        Topic = publishTopic,
                        QualityOfServiceLevel = MqttQualityOfServiceLevel.AtMostOnce,
                        Payload = Encoding.UTF8.GetBytes(messageObj),
                        Retain = false,
                    });

                    if (result.IsSuccess)
                    {
                        if (Service1.SwitchLog)
                        {
                            Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}]: {messageObj}");
                        }
                    }
                    else
                    {
                        Logger.WriteMqtt($"线程 [{source}] 发送 [{type}] 消息到主题 [{publishTopic}] 失败: {result.Message}");

                    }
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError($"发送消息错误: {ex.Message}");
            }
        }



        public void SubscribeMessage(string topic, MessageFormat format = MessageFormat.Text, bool truncateLongMessage = false)
        {
            if (!mqttIsConnected)
            {
                ConnectMqttAsync().Wait();
            }

            try
            {
                JYResult operateResult = mqttClient.SubscribeMessage(new string[] { topic });
                if (!operateResult.IsSuccess)
                {
                    Logger.WriteMqtt($"订阅消息失败: {operateResult.Message}");
                    return;
                }

                SubscribeTopic subscribeTopic = mqttClient.GetSubscribeTopic(topic);
                if (subscribeTopic != null)
                {
                    subscribeTopic.OnMqttMessageReceived += (sender, args) =>
                    {
                        HandleReceivedMessage(args.Topic, args.Payload, format, truncateLongMessage);
                    };
                    Logger.WriteMqtt($"成功订阅主题: {topic}");
                }
                else
                {
                    Logger.WriteMqtt($"无法获取订阅主题 {topic}");
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError($"订阅主题时出错 {topic}: {ex.Message}");
            }
        }

        private void HandleReceivedMessage(string topic, byte[] payload, MessageFormat format, bool truncateLongMessage)
        {
            ReceiveCount++;
            string text = string.Empty;

            try
            {
                switch (format)
                {
                    case MessageFormat.Binary:
                        text = BitConverter.ToString(payload).Replace("-", " ");
                        break;
                    case MessageFormat.Text:
                        text = Encoding.UTF8.GetString(payload);
                        break;
                    case MessageFormat.Xml:
                        try
                        {
                            text = XElement.Parse(Encoding.UTF8.GetString(payload)).ToString();
                        }
                        catch
                        {
                            text = Encoding.UTF8.GetString(payload);
                        }
                        break;
                    case MessageFormat.Json:
                        try
                        {
                            text = JObject.Parse(Encoding.UTF8.GetString(payload)).ToString();
                        }
                        catch
                        {
                            text = Encoding.UTF8.GetString(payload);
                        }
                        break;
                }
                //if (Service1.SwitchLog)
                //{
                //    LogNet.WriteDebug($"收到主题 {topic}: {text}");
                //}
                //if (truncateLongMessage && text.Length > 200)
                //{
                //    text = text.Substring(0, 200) + "...";
                //}

                string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff");
                OnMessageReceived?.Invoke(timestamp, topic, text);
            }
            catch (Exception ex)
            {
                Logger.WriteError($"处理收到的消息时出错: {ex.Message}");
            }
        }

        public void UnsubscribeMessage(string topic)
        {
            try
            {
                JYResult operateResult = mqttClient.UnSubscribeMessage(new string[] { topic });
                if (operateResult.IsSuccess)
                {
                    Logger.WriteMqtt($"成功取消订阅主题: {topic}");
                }
                else
                {
                    Logger.WriteMqtt($"取消订阅主题失败 {topic}: {operateResult.Message}");
                }
            }
            catch (Exception ex)
            {
                Logger.WriteError($"取消订阅主题时出错 {topic}: {ex.Message}");
            }
        }

        /// <summary>
        /// 重连
        /// </summary>
        /// <returns></returns>
        private async Task ReconnectWithRetry()
        {
            int attempts = 0;
            while (!mqttClient.IsConnected && attempts < MaxReconnectAttempts)
            {
                try
                {
                    await mqttClient.ConnectServerAsync();
                    Logger.WriteMqtt("重新连接成功.");

                    return;
                }
                catch (Exception ex)
                {
                    attempts++;
                    Logger.WriteMqtt($"重新连接尝试 {attempts} 失败的: {ex.Message}");
                    await Task.Delay(ReconnectDelay);
                }
            }
            if (!mqttClient.IsConnected)
            {
                Logger.WriteMqtt("尝试次数达到上限后仍无法重新连接.");
            }
        }


        private async Task ReconnectAsync()
        {
            Logger.WriteMqtt("正在尝试重新连接...");
            mqttIsConnected = false;
            int retryCount = 0;
            const int maxRetries = 5;
            const int retryDelayMs = 5000;

            while (!mqttIsConnected && retryCount < maxRetries)
            {
                try
                {
                    await ConnectMqttAsync();
                    if (mqttIsConnected)
                    {
                        Logger.WriteMqtt("重新连接成功");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    Logger.WriteMqtt($"重新连接尝试 {retryCount + 1} 失败的: {ex.Message}");
                }

                retryCount++;
                await Task.Delay(retryDelayMs);
            }

            if (!mqttIsConnected)
            {
                Logger.WriteMqtt("多次尝试后仍无法重新连接");
            }
        }



        public async Task Disconnect()
        {
            await mqttClient.ConnectCloseAsync();
            mqttIsConnected = false;
            Logger.WriteMqtt("与 MQTT服务端断开连接！！！");
        }
    }
}
